﻿
// MFCApplication7Dlg.cpp: 实现文件

#include "pch.h"
//
#include <TlHelp32.h>

#include "MFCApplication7.h"
#include "MFCApplication7Dlg.h"
#include "afxdialogex.h"
#include "framework.h"
#include "resource.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

DWORD GetPrcsIDbyName(LPCWSTR PrcsName);
HWND GetWindowHandleByPID(DWORD dwPid);
DWORD WINAPI ThreadProc(LPVOID lpParams);
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx {
   public:
    CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_ABOUTBOX };
#endif

   protected:
    virtual void DoDataExchange(CDataExchange* pDX);  // DDX/DDV 支持

    // 实现
   protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) {}

void CAboutDlg::DoDataExchange(CDataExchange* pDX) {
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

// CMFCApplication7Dlg 对话框
CMFCApplication7Dlg::CMFCApplication7Dlg(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_MFCAPPLICATION7_DIALOG, pParent), CStr_ProcessName(_T("")) {
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMFCApplication7Dlg::DoDataExchange(CDataExchange* pDX) {
    CDialogEx::DoDataExchange(pDX);
    DDX_Text(pDX, IDC_EDIT1, CStr_ProcessName);
    DDX_Text(pDX, IDC_EDIT2, CStr_WinName);
    DDX_Text(pDX, IDC_STATIC2, CStr_Pid);
    DDX_Text(pDX, IDC_STATIC3, CStr_Process);
    DDX_Text(pDX, IDC_STATIC4, CStr_HWnd);
}

BEGIN_MESSAGE_MAP(CMFCApplication7Dlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, &CMFCApplication7Dlg::OnBnClickedButton1)
ON_BN_CLICKED(IDC_BUTTON2, &CMFCApplication7Dlg::OnBnClickedButton2)
END_MESSAGE_MAP()

// CMFCApplication7Dlg 消息处理程序

BOOL CMFCApplication7Dlg::OnInitDialog() {
    CDialogEx::OnInitDialog();

    // 将“关于...”菜单项添加到系统菜单中。

    // IDM_ABOUTBOX 必须在系统命令范围内。
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != nullptr) {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty()) {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // 设置此对话框的图标。  当应用程序主窗口不是对话框时，框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);   // 设置大图标
    SetIcon(m_hIcon, FALSE);  // 设置小图标

    // TODO: 在此添加额外的初始化代码

    // 初始化控件对象
    // Edit_ProcessName = (CEdit *)GetDlgItem(IDC_EDIT1);
    // Edit_WinName = (CEdit *)GetDlgItem(IDC_EDIT2);
    // Static_Pid = (CStatic *)GetDlgItem(IDC_STATIC2);

    // 初始化控件的值
    CStr_Pid = "Pid: ";
    CStr_Process = "进程句柄: ";
    CStr_HWnd = "进程句柄: ";

    ThreadFlag = FALSE;

    UpdateData(FALSE);
    return TRUE;  // 除非将焦点设置到控件，否则返回 TRUE
}

void CMFCApplication7Dlg::OnSysCommand(UINT nID, LPARAM lParam) {
    if ((nID & 0xFFF0) == IDM_ABOUTBOX) {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    } else {
        CDialogEx::OnSysCommand(nID, lParam);
    }
}

// 如果向对话框添加最小化按钮，则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序，
//  这将由框架自动完成。

void CMFCApplication7Dlg::OnPaint() {
    if (IsIconic()) {
        CPaintDC dc(this);  // 用于绘制的设备上下文

        SendMessage(WM_ICONERASEBKGND,
                    reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // 使图标在工作区矩形中居中
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // 绘制图标
        dc.DrawIcon(x, y, m_hIcon);
    } else {
        CDialogEx::OnPaint();
    }
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMFCApplication7Dlg::OnQueryDragIcon() {
    return static_cast<HCURSOR>(m_hIcon);
}

void CMFCApplication7Dlg::OnBnClickedButton1() {
    // TODO: 在此添加控件通知处理程序代码

    if (ThreadFlag == TRUE) {
        //关闭线程函数
        ThreadFlag = FALSE;
        // SetDlgItemText(IDC_BUTTON_Open, _T("打开线程"));
        return;
    } else {
        //创建线程函数
        ThreadFlag = TRUE;
        // HANDLE hMultiThread =
        // AfxBeginThread(ThreadProc, /*(LPVOID)*/ this,
        // THREAD_PRIORITY_IDLE);
        // SetDlgItemText(IDC_EDIT_MAIN, _T("主线程开启"));
        // SetDlgItemText(IDC_BUTTON_Open, _T("关闭线程"));
        return;
    }

    // 获取当前窗口句柄
    UpdateData(TRUE);
    if (CStr_ProcessName == "") {
        if (CStr_WinName == "") {
            this->MessageBox(_T("请输入进程Id或者窗口名称!"));
            return;
        } else {
            HWND hWnd = ::FindWindowW(NULL, CStr_WinName);
            if (hWnd == NULL) {
                this->MessageBox(_T("获取窗口句柄失败!"));
                return;
            }
            gloab_hWnd = hWnd;
            CStr_HWnd.Format(_T("%d"), hWnd);
            CStr_HWnd = _T("窗口句柄: ") + CStr_HWnd;

            DWORD dwPid = -1;
            GetWindowThreadProcessId(hWnd, &dwPid);
            if (dwPid == -1) {
                this->MessageBox(_T("获取Pid失败!"));
                return;
            }
            CStr_Pid.Format(_T("%d"), dwPid);
            CStr_Pid = _T("Pid: ") + CStr_Pid;

            HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
            if (handle == 0) {
                this->MessageBox(_T("获取进程句柄失败!"));
                return;
            }
            CStr_Process.Format(_T("%d"), handle);
            CStr_Process = _T("进程句柄: ") + CStr_Process;

            UpdateData(FALSE);
        }
        return;
    } else {
        // 进程名称获取pid
        DWORD Pid = GetPrcsIDbyName(CStr_ProcessName);

        if (Pid == 0) {
            this->MessageBox(_T("获取Pid失败!"));
            return;
        }
        CStr_Pid.Format(_T("%d"), Pid);
        CStr_Pid = _T("Pid: ") + CStr_Pid;

        HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
        if (handle == 0) {
            this->MessageBox(_T("获取进程句柄失败!"));
            return;
        }
        CStr_Process.Format(_T("%d"), handle);
        CStr_Process = _T("进程句柄: ") + CStr_Process;

        HWND hwnd = GetWindowHandleByPID(Pid);
        if (hwnd == NULL) {
            this->MessageBox(_T("获取窗口句柄失败!"));
            return;
        }
        CStr_HWnd.Format(_T("%d"), hwnd);
        CStr_HWnd = _T("窗口句柄: ") + CStr_HWnd;

        UpdateData(FALSE);
    }
}

// 根据进程名称获取进程pid
DWORD GetPrcsIDbyName(LPCWSTR PrcsName) {
    HANDLE hSnapShot;
    PROCESSENTRY32 PE32;
    ZeroMemory(&PE32, sizeof(PE32));
    PE32.dwSize = sizeof(PE32);
    hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapShot == INVALID_HANDLE_VALUE) {
        return 0;
    }
    if (!Process32First(hSnapShot, &PE32)) {
        return 0;
    }
    do {
        if (lstrcmpi(PE32.szExeFile, PrcsName) == 0) {
            CloseHandle(hSnapShot);
            return PE32.th32ProcessID;
        }
    } while (Process32Next(hSnapShot, &PE32));
    CloseHandle(hSnapShot);
    return 0;
}

// 根据进程id获取窗口句柄
HWND GetWindowHandleByPID(DWORD dwPid) {
    HWND h = GetTopWindow(0);
    while (h) {
        DWORD pid = 0;
        DWORD dwTheardId = GetWindowThreadProcessId(h, &pid);
        if (dwTheardId != 0) {
            if (pid == dwPid /*your process id*/) {
                // here h is the handle to the window

                if (GetTopWindow(h)) {
                    return h;
                }
                // return h;
            }
        }
        h = ::GetNextWindow(h, GW_HWNDNEXT);
    }
    return NULL;
}

void CMFCApplication7Dlg::OnBnClickedButton2() {
    // TODO: 在此添加控件通知处理程序代码

    if (gloab_hWnd == NULL) {
        this->MessageBox(_T("请先获取窗口句柄!"));
    }
}

DWORD WINAPI ThreadProc(LPVOID lpParams) {
    CMFCApplication7Dlg* pDlg =
        (CMFCApplication7Dlg*)lpParams;  //创建一个指向主对话框的句柄

    //  while (1) {
    //     ::SetWindowPos(gloab_hWnd, HWND_TOPMOST, 0, 0, 0, 0,
    //                    SWP_NOMOVE | SWP_NOSIZE);
    //     Sleep(10);
    // }
    CString str;
    int ThreadCount = 1;
    while (pDlg->ThreadFlag) {
        str.Format(_T("子线程开启第%d次"), ThreadCount++);
        pDlg->GetDlgItem(IDC_EDIT2)->SetWindowText(str);
        Sleep(1000);  //定时1秒钟
    }
    return 0;  // AfxBeginThread线程的关闭，利用函数执行完毕后，自动返回，然后创建的线程也跟着关闭，对应资源也跟着释放。
}